<?php

namespace app\api\service;

use support\spark\model\user\User;
use EasyWeChat\Factory;
use support\Cache;
use support\spark\exception\ApiException;
use support\spark\exception\LogicException;

class LoginService
{

    protected $source_config = [
        'H5' => 4,
        'APP' => 5,
        'PC' => 3,
        'wechat' => 1,
        'applet' => 2,
    ];

    /**
     * 根据短信登录
     * @param $param
     * @return array
     */
    public function doLoginBySms($param)
    {
        if (empty($param['phone']) || empty($param['code'])) {
            throw new ApiException('手机号或验证码不能为空',-1);
        }

        // 检测验证码
        $code = Cache::get($param['phone'] . '_' . $param['type']);
        if ($param['code'] != $code) {
            throw new ApiException('验证码错误',-4);
        }
        Cache::set($param['phone'] . '_' . $param['type'], null);

        $userModel = new User();
        $userInfo = $userModel->getInfoByWhere([
            'phone' => $param['phone']
        ]);
        if (empty($userInfo)) {
            throw new ApiException('手机号不存在',-4);
        }

        if ($userInfo['status'] == 2) {
            throw new ApiException('该账号已经禁用',-4);
        }

        $token = \Tinywan\Jwt\JwtToken::generateToken($userInfo);
        if (!$token) {
            throw new ApiException('登录失败',-4);
        }
        return dataReturn(0, '登录成功', [
            'token' => $token['access_token'],
            'userInfo' => [
                'id' => $userInfo['id'],
                'name' => $userInfo['nickname'],
                'avatar' => $userInfo['avatar'],
            ]
        ]);
    }

    /**
     * 根据账号密码登录
     * @param $param
     * @return array
     */
    public function doLoginByAccount($param)
    {
        if (empty($param['phone']) || empty($param['password'])) {
            throw  new ApiException('手机号或密码不能为空', -2);
        }
        $userModel = new User();
        $userInfo = $userModel->getInfoByWhere([
            'phone' => $param['phone']
        ]);
        if (empty($userInfo)) {
            throw  new ApiException('用户名密码错误', -2);
        }
        if ($userInfo['status'] == 2) {
            throw  new ApiException('该账号已经禁用', -3);
        }
        // 比较密码
        if (makePassword($param['password']) != $userInfo['password']) {
            throw  new ApiException('用户名密码错误', -4);
        }

        $token = \Tinywan\Jwt\JwtToken::generateToken($userInfo);
        if (!$token) {
            throw new ApiException('登录失败');
        }

        return dataReturn(0, '登录成功', [
            'token' => $token['access_token'],
            'userInfo' => [
                'id' => $userInfo['id'],
                'name' => $userInfo['nickname'],
                'avatar' => $userInfo['avatar'],
            ]
        ]);
    }

    /**
     * 用户注册
     * @param $param
     * @return array
     */
    public function userReg($param)
    {
        if (empty($param['phone']) || empty($param['password'])) {
            throw new ApiException('手机号或密码不能为空', -1);
        }
        if (empty($param['code'])) {
            throw new ApiException('验证码不能为空', -2);
        }
        try {
            // 检测验证码
            $code = Cache::get($param['phone'] . '_' . $param['type']);
            if ($param['code'] != $code) {
                throw new LogicException('验证码不能为空');
            }
            Cache::set($param['phone'] . '_' . $param['type'], null);
            $userModel = new User();
            $has = $userModel->getInfoByWhere(['phone' => $param['phone']], ['id']);
            if (!empty($has)) {
                throw new LogicException('该用手机号已经注册，请直接登录');
            }
            $user_id = $this->initUser($param['phone'], $param['phone'], $param['password'], 'H5');
            $this->afterReg($user_id, $param);
        } catch (\Throwable $e) {
            throw new ApiException($e->getMessage(), -5);
        }
        return dataReturn(0, '注册成功');
    }

    /**
     * 微信授权登录
     * @param $code
     * @param $loginCode
     * @param $avatar
     * @return array
     */
    public function loginByWechat($code, $loginCode, $avatar)
    {
        $miniapp = getConfByType('miniapp');
        $res = $this->getPhoneNumberFromWx($code, $miniapp);
        $phone = $res['phone_info']['phoneNumber'];

        $userModel = new User();
        $userInfo = $userModel->getInfoByWhere([
            'phone' => $phone
        ]);
        try {
            if (empty($userInfo)) {
                $config = [
                    'app_id' => $miniapp['miniapp_app_id'],
                    'secret' => $miniapp['miniapp_app_secret'],
                ];
                $app = Factory::miniProgram($config);
                $result = $app->auth->session($loginCode);
                // 根据openid
                if (!isset($result['openid'])) {
                    throw  new  LogicException('系统错误');
                }
                $user_id = $this->initUser('微信用户', $phone, '', 'applet', $result['openid'], $avatar);
                $userInfo = [
                    'id' => $user_id,
                    'nickname' => '微信用户',
                    'avatar' => $avatar,
                ];
            }
            $token = \Tinywan\Jwt\JwtToken::generateToken($userInfo);
            if (!$token) {
                throw  new  LogicException('登录失败');
            }
        } catch (\Throwable $e) {
            throw  new  ApiException('登录失败!');
        }
        return dataReturn(0, '登录成功', [
            'token' => $token['access_token'],
            'userInfo' => [
                'id' => $userInfo['id'],
                'name' => $userInfo['nickname'],
                'avatar' => $userInfo['avatar'],
            ]
        ]);
    }

    /**
     * 从微信拿手机号
     * @param $param
     * @param $appInfo
     * @param $refresh int
     * @return array|mixed
     */
    protected function getPhoneNumberFromWx($code, $appInfo, int $refresh = 0)
    {
        $app = Factory::miniProgram([
            'app_id' => $appInfo['miniapp_app_id'],
            'secret' => $appInfo['miniapp_app_secret']
        ]);

        // 拿手机号
        $accessToken = $app->access_token;
        if ($refresh == 0) {
            $token = $accessToken->getToken(); // token 数组  token['access_token'] 字符串
        } else {
            $token = $accessToken->getToken(true); // 强刷token
        }
        $token = $token['access_token'];
        $url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=$token";

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode(['code' => $code]));
        curl_setopt($curl, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json'
        ]);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        $res = curl_exec($curl);
        curl_close($curl);

        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] == 40001) { // token过期

            if ($refresh == 1) {
                return dataReturn(-1, '系统错误');
            }

            return $this->getPhoneNumberFromWx($code, $appInfo, 1);
        }

        return $res;
    }

    /**
     * 初始化用户
     * @param $nickname  昵称
     * @param $phone     手机号
     * @param $password   密码
     * @param $source     注册来源
     * @return array
     */
    public function initUser($nickname, $phone, $password = '', $source = 'H5', $open_id = '', $avatar = '')
    {
        $domain = getConfByType('base');
        $regParam = [
            'code' => uniqid(),
            'source_id' => $this->source_config[$source] ?? 4,
            'nickname' => $nickname,
            'phone' => $phone,
            'open_id' => $open_id,
            'avatar' => !empty($avatar) ? $avatar : $domain['website_url'] . '/static/admin/default/image/avatar.png',
            'password' => $password ? makePassword($password) : '',
            'register_time' => now(),
            'create_time' => now(),
            'update_time' => now()
        ];
        return (new User())->insertOne($regParam);
    }

    /**
     * 注册后的逻辑
     * @param $user_id
     * @param $param
     * @return void
     */
    protected function afterReg($user_id, $param)
    {
        //开通分佣

        return true;
    }
}
